# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: api\handlers\frontend\__init__.py
__author__ = "Attila Gerendi (Sanyi)"
import logging, datetime
from dateutil.tz import tzlocal
from sqlalchemy import select as sql_select
from sqlalchemy import func as sql_func
from api.handlers import ResourceHandler
from db.tables.users import UserRow
from db import Connection
from db.data.users import get_user_shard, prepare_user_data, update_license
from server.http_responses.http_errors import InvalidSession
from server.routers.api.auth import ApiKeyAuth, AdminImpersonatorAuth, UiSessionAuth
from helpers.licensing.features import Features, BaseLicense
from settings_provider import settings
from helpers.rate_limiter import RateLimiter
from server.http_responses.http_errors import (
    TooManyRequests,
    Http409,
    Forbidden,
    ApiErrors,
)
from helpers.hashing import sha256
from helpers.setup_types import is_setup_type_aws, is_setup_type_on_premise
from db.tables.ui_sessions import UiSessionRow, UiSessionsTable

logger = logging.getLogger("frontend_api_resources.BaseResource")


class FrontendResourceHandler(ResourceHandler):
    def requires_master_user(self):
        if self.request_user["owner_id"] is not None:
            raise Forbidden()

    @property
    def current_shard_name(self):
        if not self.request_auth:
            raise InvalidSession()
        if self._FrontendResourceHandler__current_shard_name is None:
            self._FrontendResourceHandler__current_shard_name = get_user_shard(
                user_id=self.request_auth.user_id
            )
        return self._FrontendResourceHandler__current_shard_name

    @property
    def request_user_id(self):
        return self.request_user["user_id"]

    @property
    def request_owner_id(self):
        owner_id = self.request_user["owner_id"]
        if owner_id is None:
            owner_id = self.request_user["user_id"]
        return owner_id

    @property
    def is_request_by_master_account(self):
        return self.request_user["owner_id"] is None

    @property
    def request_user(self):
        if self._FrontendResourceHandler__request_user:
            return self._FrontendResourceHandler__request_user
        else:
            with Connection(self.current_shard_name) as (db):
                is_admin_impersonated = False
                user = prepare_user_data(db, user_id=self.request_auth.user_id)
                if user is None:
                    raise InvalidSession()
                if isinstance(self.request_auth, AdminImpersonatorAuth):
                    q = (
                        sql_select((UserRow.extra, UserRow.password, UserRow.user_id))
                        .where(UserRow.user_id == self.request_auth.admin_id)
                        .where(UserRow.deleted_at.is_(None))
                        .where(UserRow.enabled.is_(True))
                    )
                    admin = db.execute(q).fetchone()
                    if not admin:
                        raise InvalidSession()
                    admin_extra = admin.extra.get("admin")
                    if not admin_extra:
                        raise InvalidSession()
                    if not admin_extra.get("impersonator"):
                        raise InvalidSession()
                    if self.request_auth.admin_auth != sha256(
                        admin.password, UiSessionAuth.SESSION_SECRET
                    ):
                        raise InvalidSession()
                    if self.request_auth.user_id != user["user_id"].replace("-", ""):
                        raise InvalidSession()
                    is_admin_impersonated = True
                else:
                    if isinstance(self.request_auth, ApiKeyAuth):
                        if not user["api_key"]:
                            raise InvalidSession()
                if is_setup_type_aws():
                    if user["license_type"] == "customer":
                        last_refresh = user["license_data"]["last_refresh"]
                        if last_refresh:
                            if datetime.datetime.now(tzlocal()) - last_refresh < (
                                datetime.timedelta(hours=24)
                            ):
                                pass
                            update_license(
                                license_key=user["license_key"],
                                shard_name=self.current_shard_name,
                            )
                    else:
                        raise InvalidSession()
                else:
                    if user["api_key_enabled"]:
                        pass
                    else:
                        logger.debug("no api key enabled")
                        raise InvalidSession()
                    rt_api_key_brute_force = settings.get("rt_api_key_brute_force")
                    if rt_api_key_brute_force:
                        r = rt_api_key_brute_force.wait_time(self.remote_address)
                        if r:
                            raise TooManyRequests(r)
                    ph = settings["api_key_hashing_strategy"]
                    api_key = ph(user["api_key"], settings.get("password_hash_salt"))[
                        :32
                    ]
                    if api_key != self.request_auth.api_key:
                        if rt_api_key_brute_force:
                            rt_api_key_brute_force.add(self.remote_address)
                        logger.debug("api key different")
                        raise InvalidSession()
                    self._FrontendResourceHandler__license = BaseLicense.get_license_from_license_data(
                        user["license_data"]
                    )
                    self._FrontendResourceHandler__license.require(
                        feature=Features.API_KEY
                    )
                if not self._FrontendResourceHandler__license.can_license_log_in():
                    if self._FrontendResourceHandler__license.is_poc_license():
                        raise InvalidSession(code=ApiErrors.LICENSE_POC_EXPIRED)
                    else:
                        raise InvalidSession(code=ApiErrors.LICENSE_EXPIRED)
                    if not is_admin_impersonated:
                        if not user["enabled"]:
                            raise InvalidSession(code=ApiErrors.ACCOUNT_DISABLED)
                        if not self._FrontendResourceHandler__license:
                            self._FrontendResourceHandler__license = BaseLicense.get_license_from_license_data(
                                user["license_data"]
                            )
                        if (
                            not self._FrontendResourceHandler__license.can_license_log_in()
                        ):
                            if self._FrontendResourceHandler__license.is_poc_license():
                                raise InvalidSession(code=ApiErrors.LICENSE_POC_EXPIRED)
                            else:
                                raise InvalidSession(code=ApiErrors.LICENSE_EXPIRED)
                            if self.request_auth.has_session_support:
                                q = sql_select(
                                    (
                                        UiSessionRow.validity,
                                        (
                                            UiSessionRow.expires
                                            < sql_func.current_timestamp()
                                        ).label("expired"),
                                    )
                                ).where(UiSessionRow.key == self.request_auth.key)
                                r = db.execute(q).fetchone()
                                if r is None:
                                    rt_session_brute_force = settings.get(
                                        "rt_session_brute_force"
                                    )
                                    if rt_session_brute_force:
                                        rt_session_brute_force.add(
                                            self.request_auth.remote_address
                                        )
                                    raise InvalidSession()
                                if r.expired:
                                    q = UiSessionsTable.delete().where(
                                        UiSessionRow.key == self.request_auth.key
                                    )
                                    db.execute(q)
                                    raise InvalidSession()
            if is_admin_impersonated:
                rt_api_request = None
            else:
                if user["license_type"] == "customer":
                    rt_api_request = settings.get("rt_customer_api_request")
                else:
                    rt_api_request = settings.get("rt_api_request")
            if rt_api_request:
                r = rt_api_request.wait_time(user["email"])
                if r:
                    raise TooManyRequests(r)
                r = rt_api_request.add(user["email"])
                if r:
                    raise TooManyRequests(r)
            self._FrontendResourceHandler__request_user = user
            return self._FrontendResourceHandler__request_user

    @property
    def license(self):
        if self._FrontendResourceHandler__license is None:
            if is_setup_type_aws():
                self._FrontendResourceHandler__license = BaseLicense.get_license_from_license_data(
                    self.request_user["license_data"]
                )
            else:
                if is_setup_type_on_premise():
                    self._FrontendResourceHandler__license = (
                        BaseLicense.get_system_license()
                    )
            return self._FrontendResourceHandler__license

    def __init__(self, request_auth, base_path, remote_address, **_):
        """
        :param request_auth:
        :param _:
        :return:
        """
        super().__init__()
        self.request_auth = request_auth
        self.remote_address = remote_address
        self.base_path = base_path
        self._FrontendResourceHandler__license = None
        self._FrontendResourceHandler__request_user = None
        self._FrontendResourceHandler__current_shard_name = None
